package com.jappit.runtracker.data;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.util.Date;

import javax.microedition.rms.RecordEnumeration;
import javax.microedition.rms.RecordStore;

import com.jappit.runtracker.model.Run;
import com.jappit.runtracker.model.RunSet;
import com.nokia.maps.common.GeoCoordinate;

public class DataManager
{
	RunSet runs = null;
	
	final String RMS_NAME = "runs_data";
	
	static DataManager instance = null;
	
	DataManager()
	{
		
	}
	public static DataManager getInstance()
	{
		if(instance == null)
		{
			instance = new DataManager();
		}
		return instance;
	}
	
	public RunSet getRuns()
	{
		return runs;
	}
	
	public void loadRuns()
	{
		RecordStore runStore = null;
		
		try
		{
			runStore = RecordStore.openRecordStore(RMS_NAME, true);
			
			RecordEnumeration enumerator = runStore.enumerateRecords(null, null, false);
			
			int recNum = enumerator.numRecords();
			
			runs = new RunSet();
			
			for(int i = 0; i < recNum; i++)
			{
				int recId = enumerator.nextRecordId();
				
				Run run = DataManager.deserialize(runStore.getRecord(recId));
				
				System.out.println("COORDS: " + run.getCoordinatesNum() + ", " + run.getDistance());
				
				run.rmsId = recId;
				
				runs.addRun(run);
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		finally
		{
			try
			{
				runStore.closeRecordStore();
			}
			catch(Exception e)
			{
				
			}
		}
	}
	public void addRun(Run run) throws Exception
	{
		if(runs == null)
			throw new Exception("Runs still not loaded");
		
		RecordStore runStore = null;
		
		try
		{
			runStore = RecordStore.openRecordStore(RMS_NAME, true);
			
			byte[] data = serialize(run);
			
			System.out.println("COORDS: " + run.getCoordinatesNum() + ", " + run.getDistance());
			
			run.rmsId = runStore.getNextRecordID();
			
			runStore.addRecord(data, 0, data.length);
			
			runs.addRun(run);
		}
		catch(Exception e)
		{
			
		}
		finally
		{
			try
			{
				runStore.closeRecordStore();
			}
			catch(Exception e)
			{
				
			}
		}
	}
	public void removeRun(Run run) throws Exception
	{
		if(runs == null)
			throw new Exception("Runs still not loaded");
		
		RecordStore runStore = null;
		
		try
		{
			runStore = RecordStore.openRecordStore(RMS_NAME, true);
			
			runStore.deleteRecord(run.rmsId);
			
			runs.removeRun(run);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		finally
		{
			try
			{
				runStore.closeRecordStore();
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
	}
	
	static byte[] serialize(Run run)
	{
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		DataOutputStream dos = new DataOutputStream(bos);
		
		byte[] res = null;
		
		try
		{
			dos.writeLong(run.getStartDate().getTime());
			dos.writeLong(run.getEndDate().getTime());
			dos.writeFloat(run.getDistance());
			dos.writeInt(run.getCoordinatesNum());
			
			for(int i = 0, num = run.getCoordinatesNum(); i < num; i++)
			{
				GeoCoordinate coord = run.getCoordinate(i);
				dos.writeDouble(coord.getLatitude());
				dos.writeDouble(coord.getLongitude());
				dos.writeFloat((float)coord.getAltitude());
			}
			
			res = bos.toByteArray();
		}
		catch(Exception e)
		{
			
		}
		finally
		{
			try
			{
				dos.close();
				bos.close();
			}
			catch(Exception e)
			{
				
			}
		}
		return res;
	}
	static Run deserialize(byte[] bytes)
	{
		ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
		DataInputStream dis = new DataInputStream(bis);
		
		Run run = null;
		
		try
		{
			run = new Run();
			
			long startTime = dis.readLong();
			long endTime = dis.readLong();
			float distance = dis.readFloat();
			int coordsNum = dis.readInt();
			
			//run.setDistance(distance);
			
			for(int i = 0; i < coordsNum; i++)
			{
				GeoCoordinate coord = new GeoCoordinate(dis.readDouble(), dis.readDouble(), dis.readFloat());
				
				run.addCoordinate(coord);
			}
			
			run.setStartDate(new Date(startTime));
			run.setEndDate(new Date(endTime));
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		finally
		{
			try
			{
				dis.close();
				bis.close();
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
		return run;
	}
}
